﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bymed.SpineScan.Service.Shared
{
    public class ConfiguredNumberHelper
    {
        public string Number { get; private set; }
        public string FullPrefix { get; private set; }
        public string InitialSequenceNumber { get; private set; }
        public int FixedLength { get; private set; }
        public bool IsAutoExtended { get; private set; }
        private bool _containsYear;
        private bool _containsMonth;
        private bool _containsDay;
        private string _prefixConfigName;
        private string _containsYearConfigName;
        private string _containsMonthConfigName;
        private string _containsDayConfigName;
        private string _initialSequenceNumberConfigName;
        private string _yearPrefix;
        private string _monthPrefix;
        private string _dayPrefix;

        public ConfiguredNumberHelper(string prefixConfigName, string containsYearConfigName,
            string containsMonthConfigName, string containsDayConfigName, string initialSequenceNumberConfigName)
        {
            _prefixConfigName = prefixConfigName;
            _containsYearConfigName = containsYearConfigName;
            _containsMonthConfigName = containsMonthConfigName;
            _containsDayConfigName = containsDayConfigName;
            _initialSequenceNumberConfigName = initialSequenceNumberConfigName;
            _yearPrefix = "yyyy";
            _monthPrefix = "MM";
            _dayPrefix = "dd";

            InitialSequenceNumber = (string)ConfigFileUtility.GetValue(_initialSequenceNumberConfigName);

            GetFullPrefix();

            FixedLength += InitialSequenceNumber.Length;
        }

        /// <summary>
        /// Generate new number based on configured parameters.
        /// </summary>
        /// <param name="currentMaxNumber">The current max number.</param>
        /// <returns>Generated new number.</returns>
        public string GenerateNewNumber(string currentMaxNumber)
        {
            if (string.IsNullOrEmpty(currentMaxNumber))
            {
                // If there is NO existing number with the same full prefix

                Number = FullPrefix + InitialSequenceNumber;
            }
            else
            {
                // Get current sequence based on current max number
                var currentSequence = GetCurrentMaxSequence(currentMaxNumber);

                // Come with new sequence
                var newSequence = currentSequence + 1;

                // Generate new sequence number based on initial sequence number lengh
                var newSequenceNumber = newSequence.ToString().PadLeft(InitialSequenceNumber.Length, '0');

                // If new sequence number length is greater than initial sequence number lenght
                // Need to change the initial sequence
                if (newSequenceNumber.Length > InitialSequenceNumber.Length)
                {
                    // Get the initial sequence
                    var initialSequence = int.Parse(InitialSequenceNumber);

                    // Generate new sequence based on extended length
                    InitialSequenceNumber = initialSequence.ToString().PadLeft(newSequenceNumber.Length, '0');

                    // Change the value in config file
                    ConfigFileUtility.ChangeValue(_initialSequenceNumberConfigName, InitialSequenceNumber);

                    // Mark as sequence number has been auto extended
                    IsAutoExtended = true;
                }

                Number = FullPrefix + newSequenceNumber;
            }

            return Number;
        }

        /// <summary>
        /// Get the full prefix of the number. Caculate the FixedLength based on date format.
        /// </summary>
        private void GetFullPrefix()
        {
            // Get the configured prefix
            var prefix = (string)ConfigFileUtility.GetValue(_prefixConfigName);
            FixedLength = prefix.Length;

            // Get the date format for full prefix
            var dateFormat = GetDateFormat();

            // Come with full prefix
            FullPrefix = prefix + dateFormat;
        }

        /// <summary>
        /// Get current max sequence based on provided string value of current max number.
        /// </summary>
        /// <param name="currentMaxNumber">Provided string value of current max number.</param>
        /// <returns>Current max sequence.</returns>
        private int GetCurrentMaxSequence(string currentMaxNumber)
        {
            if (!string.IsNullOrEmpty(FullPrefix))
            {
                currentMaxNumber = currentMaxNumber.Replace(FullPrefix, string.Empty);
            }

            return int.Parse(currentMaxNumber);
        }

        /// <summary>
        /// Get the date format based on the configured setting.
        /// </summary>
        /// <returns>The formatted date string.</returns>
        private string GetDateFormat()
        {
            _containsYear = Convert.ToBoolean(ConfigFileUtility.GetValue(_containsYearConfigName));
            _containsMonth = Convert.ToBoolean(ConfigFileUtility.GetValue(_containsMonthConfigName));
            _containsDay = Convert.ToBoolean(ConfigFileUtility.GetValue(_containsDayConfigName));

            string dateFormat = string.Empty;
            DateTime currentDate = GeneralUtility.GetCurrentDateTime();

            if (_containsYear)
            {
                dateFormat += _yearPrefix;
                FixedLength += _yearPrefix.Length;
            }

            if (_containsMonth)
            {
                dateFormat += _monthPrefix;
                FixedLength += _monthPrefix.Length;
            }

            if (_containsDay)
            {
                dateFormat += _dayPrefix;
                FixedLength += _dayPrefix.Length;
            }

            return string.IsNullOrEmpty(dateFormat) ? string.Empty : currentDate.ToString(dateFormat);
        }
    }
}
